package cn.zwy.asm;

import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.F_SAME;
import static org.objectweb.asm.Opcodes.GETFIELD;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.IFLT;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.PUTFIELD;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V1_8;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

public class GenerateClass extends ClassLoader{
	public static byte[] generate() {
	    ClassWriter cw = new ClassWriter(0);
//	    TraceClassVisitor tcv = new TraceClassVisitor(cw, printWriter);
//	    CheckClassAdapter cv = new CheckClassAdapter(tcv);
	    cw.visit(V1_8, ACC_PUBLIC, "cn/zwy/asm/DeptBean", null, "java/lang/Object",
	        null);
	    cw.visitSource("Bean.java", null);
	    FieldVisitor fv = cw.visitField(ACC_PRIVATE, "f", "I", null, null);
	    if (fv != null) {
	      fv.visitEnd();
	    }
	    MethodVisitor mv;
	    mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
	    if (mv != null) {
	      mv.visitCode();
	      mv.visitVarInsn(ALOAD, 0);
	      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
	          "()V", false);
	      mv.visitInsn(RETURN);
	      mv.visitMaxs(1, 1);
	      mv.visitEnd();
	    }
//	    mv = cw.visitMethod(ACC_PUBLIC, "getF", "()I", null, null);
//	    if (mv != null) {
//	      mv.visitCode();
//	      mv.visitVarInsn(ALOAD, 0);
//	      mv.visitFieldInsn(GETFIELD, "cn/zwy/asm/DeptBean", "f", "I");
//	      mv.visitInsn(IRETURN);
//	      mv.visitMaxs(1, 1);
//	      mv.visitEnd();
//	    }
//	    mv = cw.visitMethod(ACC_PUBLIC, "setF", "(I)V", null, null);
//	    if (mv != null) {
//	      mv.visitCode();
//	      mv.visitVarInsn(ALOAD, 0);
//	      mv.visitVarInsn(ILOAD, 1);
//	      mv.visitFieldInsn(PUTFIELD, "cn/zwy/asm/DeptBean", "f", "I");
//	      mv.visitInsn(RETURN);
//	      mv.visitMaxs(2, 2);
//	      mv.visitEnd();
//	    }
//	    mv = cw.visitMethod(ACC_PUBLIC, "checkAndSetF", "(I)V", null, null);
//	    if (mv != null) {
//	      mv.visitCode();
//	      mv.visitVarInsn(ILOAD, 1);
//	      Label label = new Label();
//	      mv.visitJumpInsn(IFLT, label);
//	      mv.visitVarInsn(ALOAD, 0);
//	      mv.visitVarInsn(ILOAD, 1);
//	      mv.visitFieldInsn(PUTFIELD, "cn/zwy/asm/DeptBean", "f", "I");
//	      Label end = new Label();
//	      mv.visitJumpInsn(GOTO, end);
//	      mv.visitLabel(label);
//	      mv.visitFrame(F_SAME, 0, null, 0, null);
//	      mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
//	      mv.visitInsn(DUP);
//	      mv.visitMethodInsn(INVOKESPECIAL,
//	          "java/lang/IllegalArgumentException", "<init>", "()V");
//	      mv.visitInsn(ATHROW);
//	      mv.visitLabel(end);
//	      mv.visitFrame(F_SAME, 0, null, 0, null);
//	      mv.visitInsn(RETURN);
//	      mv.visitMaxs(2, 2);
//	      mv.visitEnd();
//	    }
	    cw.visitEnd();
	    return cw.toByteArray();
	  }

	@SuppressWarnings("rawtypes")
	public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {
		String path = GenerateClass.class.getResource(".").getPath(); 
		System.out.println(path);
		FileOutputStream fileOutputStream = new FileOutputStream(new File(path , "DeptBean.class"));
		fileOutputStream.write(generate());
		fileOutputStream.flush();
		fileOutputStream.close();
		
		Class clazz = getSystemClassLoader().loadClass("cn.zwy.asm.DeptBean");
		Object obj = clazz.newInstance();
		Field field = clazz.getDeclaredField("f");
		field.setAccessible(true);
		field.set(obj, 5);
		Object value = field.get(obj);
		System.out.println(value);
	}
}
